{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 简介\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>YiJingFramework.PrimitiveTypes, 4.0.1</span></li></ul></div></div>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#r \"nuget:YiJingFramework.PrimitiveTypes\"\n",
    "using YiJingFramework.PrimitiveTypes;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此包提供了一些关于易学的基本类型，包括阴阳、五行、天干、地支和卦等。这些类型都有比较完整的字符串转换、整形转换、相互比较等功能。不过，这个包的目的是提供类型本身而非它们相互之间的关联，比如没有取干支阴阳五行、判断五行生克等功能。这些功能被置于 [YiJingFramework.EntityRelations](https://yjfwk.yueyinqiu.top/EntityRelations/) 中。\n",
    "\n",
    "## 五行\n",
    "\n",
    "以五行为例，可以用以下方式直接获取 `Wuxing`，或者把字符串和整形数字转换为 `Wuxing`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mu\n",
      "Shui\n",
      "Jin\n",
      "Huo\n"
     ]
    }
   ],
   "source": [
    "var mu = Wuxing.Mu;\n",
    "Console.WriteLine(mu);\n",
    "\n",
    "var shui = Wuxing.Parse(\" 水 \\t \");\n",
    "Console.WriteLine(shui);\n",
    "\n",
    "_ = Wuxing.TryParse(\" jin \\t \", out var jin);\n",
    "Console.WriteLine(jin);\n",
    "\n",
    "var huo = (Wuxing)6;\n",
    "Console.WriteLine(huo);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "虽然五行只有五个，但是倒数第二行的 `(Wuxing)6` 也可以正常运行。其具体的转化方式是这样的：\n",
    "\n",
    "|`i`|`w=(Wuxing)i`|`(int)w`|\n",
    "|:-:|:-:|:-:|\n",
    "|...|...|...|\n",
    "|-2|金|3|\n",
    "|-1|水|4|\n",
    "|**0**|**木**|**0**|\n",
    "|**1**|**火**|**1**|\n",
    "|**2**|**土**|**2**|\n",
    "|**3**|**金**|**3**|\n",
    "|**4**|**水**|**4**|\n",
    "|5|木|0|\n",
    "|6|火|1|\n",
    "|...|...|...|\n",
    "\n",
    "这种转换主要是可以利用于直接用数学上的计算来获取生克之类，以及更方便通过 `switch` 进行匹配。一般情况下是不建议使用的，因为这些数字没有直接的实际意义。其提供的运算符 `+` 和 `-` 也是如此。\n",
    "\n",
    "同时，其默认的 `ToString` 行为是转为首字母大写的拼音。可以传入 `\"C\"` 以使用中文："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mu木\n",
      "Huo火\n",
      "Tu土\n",
      "Jin金\n",
      "Shui水\n"
     ]
    }
   ],
   "source": [
    "Console.Write(Wuxing.Mu.ToString(\"G\"));\n",
    "Console.WriteLine(Wuxing.Mu.ToString(\"C\"));\n",
    "\n",
    "Console.Write(Wuxing.Huo);\n",
    "Console.WriteLine($\"{Wuxing.Huo:C}\");\n",
    "\n",
    "Console.Write(Wuxing.Tu);\n",
    "Console.WriteLine($\"{Wuxing.Tu:C}\");\n",
    "\n",
    "Console.Write(Wuxing.Jin);\n",
    "Console.WriteLine($\"{Wuxing.Jin:C}\");\n",
    "\n",
    "Console.Write(Wuxing.Shui);\n",
    "Console.WriteLine($\"{Wuxing.Shui:C}\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 其他语言不会在这个包中支持，不过自己实现一个方法也是相对方便的，也可以借助 [YiJingFramework.EntityRelations](https://yjfwk.yueyinqiu.top/EntityRelations/) 提供的扩展方法加以支持。\n",
    "\n",
    "`Wuxing` 提供的 `Parse` 和 `TryParse` 方法，可以解析以上所有的结果，不区分大小写，首尾可以有空白字符。\n",
    "\n",
    "除此之外，`Wuxing` 实现了 `IComparable` 、 `IEquatable` 和 `IEqualityOperators` 等接口，可以正确地支持排序和比较等行为，可以使用 `==` 等运算符进行比较。\n",
    "\n",
    "## 天干地支\n",
    "\n",
    "`Tiangan` 和 `Dizhi` 与 `Wuxing` 是非常相似的："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Jia Yi Bing 丁戊癸\r\n"
     ]
    }
   ],
   "source": [
    "var jia = Tiangan.Jia;\n",
    "var yi = jia + 1;\n",
    "var bing = yi.Next();\n",
    "var ding = jia + 13;\n",
    "var wu = ding.Next(-9);\n",
    "\n",
    "var gui = jia - 1;\n",
    "\n",
    "Console.WriteLine($\"{jia} {yi} {bing} {ding:C}{wu:C}{gui:C}\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "干支也支持超过范围的值。但是与五行不同，它的序数是具有一定意义的，因此提供了 `Index` 属性和 `FromIndex` 方法。它的值是从 `1` 开始的，具体如下表：\n",
    "\n",
    "|`i`|`t=Tiangan.FromIndex(i)`|`t.Index`|\n",
    "|:-:|:-:|:-:|\n",
    "|...|...|...|\n",
    "|-1|壬|9|\n",
    "|0|癸|10|\n",
    "|**1**|**甲**|**1**|\n",
    "|**2**|**乙**|**2**|\n",
    "|**3**|**丙**|**3**|\n",
    "|**4**|**丁**|**4**|\n",
    "|**5**|**戊**|**5**|\n",
    "|**6**|**己**|**6**|\n",
    "|**7**|**庚**|**7**|\n",
    "|**8**|**辛**|**8**|\n",
    "|**9**|**壬**|**9**|\n",
    "|**10**|**癸**|**10**|\n",
    "|11|甲|1|\n",
    "|12|乙|2|\n",
    "|...|...|...|\n",
    "\n",
    "|`i`|`d=Dizhi.FromIndex(i)`|`d.Index`|\n",
    "|:-:|:-:|:-:|\n",
    "|...|...|...|\n",
    "|-1|戌|11|\n",
    "|0|亥|12|\n",
    "|**1**|**子**|**1**|\n",
    "|**2**|**丑**|**2**|\n",
    "|**3**|**寅**|**3**|\n",
    "|**4**|**卯**|**4**|\n",
    "|**5**|**辰**|**5**|\n",
    "|**6**|**巳**|**6**|\n",
    "|**7**|**午**|**7**|\n",
    "|**8**|**未**|**8**|\n",
    "|**9**|**申**|**9**|\n",
    "|**10**|**酉**|**10**|\n",
    "|**11**|**戌**|**11**|\n",
    "|**12**|**亥**|**12**|\n",
    "|13|子|1|\n",
    "|14|丑|2|\n",
    "|...|...|...|\n",
    "\n",
    "不过，由于结构体的限制，在使用 `default` 进行创建时，其内部值会为零。因此，上述操作必然是存在额外开销的。考虑到这一问题，我们仍然提供了强制转换运算符，而它返回的结果始终是 `Index - 1`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "01子\n",
      "0子\n"
     ]
    }
   ],
   "source": [
    "Console.Write((int)default(Wuxing));\n",
    "Console.Write(default(Tiangan).Index);\n",
    "Console.WriteLine(Dizhi.FromIndex(1).ToString(\"C\"));\n",
    "\n",
    "Console.Write((int)default(Tiangan));\n",
    "Console.WriteLine(((Dizhi)0).ToString(\"C\"));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "上两例也可以看到，`ToString` 方法也支持拼音和中文两种，具体结果如下表：\n",
    "\n",
    "|天干|默认或`\"G\"`|`\"C\"`|\n",
    "|:-:|:-:|:-:|\n",
    "|甲|`\"Jia\"`|`\"甲\"`|\n",
    "|乙|`\"Yi\"`|`\"乙\"`|\n",
    "|丙|`\"Bing\"`|`\"丙\"`|\n",
    "|丁|`\"Ding\"`|`\"丁\"`|\n",
    "|戊|`\"Wu\"`|`\"戊\"`|\n",
    "|己|`\"Ji\"`|`\"己\"`|\n",
    "|庚|`\"Geng\"`|`\"庚\"`|\n",
    "|辛|`\"Xin\"`|`\"辛\"`|\n",
    "|壬|`\"Ren\"`|`\"壬\"`|\n",
    "|癸|`\"Gui\"`|`\"癸\"`|\n",
    "\n",
    "|地支|默认或`\"G\"`|`\"C\"`|\n",
    "|:-:|:-:|:-:|\n",
    "|子|`\"Zi\"`|`\"子\"`|\n",
    "|丑|`\"Chou\"`|`\"丑\"`|\n",
    "|寅|`\"Yin\"`|`\"寅\"`|\n",
    "|卯|`\"Mao\"`|`\"卯\"`|\n",
    "|辰|`\"Chen\"`|`\"辰\"`|\n",
    "|巳|`\"Si\"`|`\"巳\"`|\n",
    "|午|`\"Wu\"`|`\"午\"`|\n",
    "|未|`\"Wei\"`|`\"未\"`|\n",
    "|申|`\"Shen\"`|`\"申\"`|\n",
    "|酉|`\"You\"`|`\"酉\"`|\n",
    "|戌|`\"Xu\"`|`\"戌\"`|\n",
    "|亥|`\"Hai\"`|`\"亥\"`|\n",
    "\n",
    "\n",
    "## 阴阳\n",
    "\n",
    "阴阳由于只存在两者可能，因此 `Yinyang` 与先前的五行和干支略有不同，内部是使用布尔值来表示的。对外它提供 `IsYang` 属性取得此值，也提供了相对应的构造方法。\n",
    "\n",
    "除此之外，它不支持加减运算，但是支持布尔类型所具有的 `!` 运算符，以及 `&` 、 `|` 和 `^` 运算。不过，我们不打算为它实现 `operator true` 和 `operator false` ，因为它本身并不是一个布尔值。\n",
    "\n",
    "具体 `Yinyang` 的 `ToString` 结果如下表：\n",
    "\n",
    "|阴阳|默认或`\"G\"`|`\"C\"`|\n",
    "|:-:|:-:|:-:|\n",
    "|阴|`\"Yin\"`|`\"阴\"`|\n",
    "|阳|`\"Yang\"`|`\"阳\"`|\n",
    "\n",
    "## 卦\n",
    "\n",
    "卦是由若干具有阴阳属性的爻组成的。通常来说，我们常用的是具有三根爻的八卦和六根爻的六十四卦，但是这里给出的 `Gua` 支持任意的爻数。\n",
    "\n",
    "> [YiJingFramework.PrimitiveTypes.GuaWithFixedCount](https://yjfwk.yueyinqiu.top/PrimitiveTypes.GuaWithFixedCount/) 提供了只支持固定爻数的卦，从而能够及时在编译期发现错误。\n",
    "\n",
    "`Gua` 其实就是一个不可变的有序的爻的集合，可以通过以下方式来创建 `Gua`：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "110\n",
      "111111\n"
     ]
    }
   ],
   "source": [
    "var dui = new Gua(Yinyang.Yang, Yinyang.Yang, Yinyang.Yin);\n",
    "Console.WriteLine(dui);\n",
    "\n",
    "var qian = new Gua(Enumerable.Repeat(Yinyang.Yang, 6));\n",
    "Console.WriteLine(qian);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意：虽然顺序本身是可以颠倒的，但是使用时请统一按照序号小的在下、序号大的在上，即易气上行、先来居下、由下至上的顺序（所谓上下即常用的卦画的上下），如上例“阳阳阴”表示兑卦而非巽卦。包括 [YiJingFramework.EntityRelations](https://yjfwk.yueyinqiu.top/EntityRelations/) 和 [YiJingFramework.Annotating.Zhouyi](https://yjfwk.yueyinqiu.top/Annotating.Zhouyi/) 在内的各种包，都是按照由下至上的理解方式来提供功能的。**\n",
    "\n",
    "`Gua` 实现了 `IReadOnlyList` ，因此可以当作列表使用。无论是通过索引器访问，还是通过 `foreach` 遍历，都是由下至上的顺序："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "110\n",
      "Yang Yang Yin\n",
      "Yang,Yang,Yin\n"
     ]
    }
   ],
   "source": [
    "var dui = new Gua(Yinyang.Yang, Yinyang.Yang, Yinyang.Yin);\n",
    "\n",
    "Console.WriteLine(dui);\n",
    "Console.WriteLine($\"{dui[0]} {dui[1]} {dui[2]}\");\n",
    "Console.WriteLine($\"{string.Join(',', dui)}\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "上例中我们也已经看到了 `Gua.ToString` 的效果，它使用 `'1'` 表示阳爻、 `'0'` 表示阴爻，从而把卦转为一个相对简短的字符串，也是先下后上的顺序。\n",
    "\n",
    "同时，它也实现了 `Parse` 和 `TryParse` 等方法，以及 `IComparable` 、 `IEquatable` 和 `IEqualityOperators` 等接口，可以使用 `==` 等运算符进行比较。\n",
    "\n",
    "最后， `Gua` 还可以被转换为 `byte[]`：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "111101101000101011101110111110\n",
      "6F51775F\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "static IEnumerable<Yinyang> GetRandomLines()\n",
    "{\n",
    "    Random random = new Random(0);\n",
    "    for (; ; )\n",
    "        yield return (Yinyang)random.Next(0, 2);\n",
    "}\n",
    "\n",
    "var gua = new Gua(GetRandomLines().Take(30));\n",
    "Console.WriteLine(gua);\n",
    "\n",
    "var byteArray = gua.ToBytes();\n",
    "Console.WriteLine(Convert.ToHexString(byteArray));\n",
    "\n",
    "var gua2 = Gua.FromBytes(byteArray);\n",
    "Console.WriteLine(gua == gua2);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "不过，这种转换一般只会在非常特殊的场合下使用。而且即使需要使用，一般也不需要关注得到的 `byte[]` 具体是什么值，只需要知道它可以正确还原就足够了。如果确实想要了解相关细节，可以点击[这里](./implementation_details_of_Gua.ToBytes.ipynb)。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "file_extension": ".cs",
   "mimetype": "text/x-csharp",
   "name": "python",
   "pygments_lexer": "csharp",
   "version": "3.12.2"
  },
  "polyglot_notebook": {
   "kernelInfo": {
    "defaultKernelName": "csharp",
    "items": [
     {
      "aliases": [],
      "name": "csharp"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
